package cn.tuling.v3;

/**
 * v2版本是从电梯的方法以及这些方法执行的条件去分析，现在换个角度。
 * <p>
 * 从状态角度，思考两个问题：
 * 1. 什么导致了当前状态
 * 2. 当前状态还能做什么？（也就是当前状态如何转化到其他状态）
 * <p>
 * 好处：
 * 1. 通过状态子类分摊代码逻辑，代码变短，易于维护
 * 2. 符合“开闭原则”，如果要增加状态，只需增加对应的子类，同时修改已实现类的响应方法，因为是增加方法，不去做修改，很安全。
 */
public class StateTest {
    public static void main(String[] args) {
        LiftContext context = new LiftContext();
        context.setLiftState(LiftContext.STOPPING_STATE);
        context.open();
        context.close();
        context.run();
        context.stop();
    }
}

/**
 * 定义Context类的好处：
 * 1. 串联各种状态，方便切换，符合“单一职责原则”，每个实现类只需要实现自己的“当前状态还能做什么？”即可，且不必聚合其他状态的类。
 * 2. 封装电梯对象内部状态变化，不让调用类知道，符合“迪米特法则”
 */
class LiftContext {
    public final static OpeningState OPENING_STATE = new OpeningState();
    public final static ClosingState CLOSING_STATE = new ClosingState();
    public final static RunningState RUNNING_STATE = new RunningState();
    public final static StoppingState STOPPING_STATE = new StoppingState();

    private LiftState liftState;

    public void setLiftState(LiftState liftState) {
        this.liftState = liftState;
        // 把当前环境通知到各个实现类
        this.liftState.setContext(this);
    }

    public LiftState getLiftState() {
        return liftState;
    }

    public void open() {
        this.liftState.open();
    }

    public void close() {
        this.liftState.close();
    }

    public void run() {
        this.liftState.run();
    }

    public void stop() {
        this.liftState.stop();
    }
}

abstract class LiftState {
    protected LiftContext context;

    public void setContext(LiftContext context) {
        this.context = context;
    }

    abstract void open();

    abstract void close();

    abstract void run();

    abstract void stop();
}

class OpeningState extends LiftState {

    @Override
    void open() {
        System.out.println("电梯门开启");
    }

    @Override
    void close() {
        context.setLiftState(LiftContext.CLOSING_STATE);
        context.getLiftState().close();
    }

    @Override
    void run() {

    }

    @Override
    void stop() {

    }
}

class ClosingState extends LiftState {

    @Override
    void open() {
        context.setLiftState(LiftContext.OPENING_STATE);
        context.getLiftState().open();
    }

    @Override
    void close() {
        System.out.println("电梯门关闭");
    }

    @Override
    void run() {
        context.setLiftState(LiftContext.RUNNING_STATE);
        context.getLiftState().run();
    }

    @Override
    void stop() {
        context.setLiftState(LiftContext.STOPPING_STATE);
        context.getLiftState().stop();
    }
}

class RunningState extends LiftState {

    @Override
    void open() {

    }

    @Override
    void close() {

    }

    @Override
    void run() {
        System.out.println("电梯运行中");
    }

    @Override
    void stop() {
        context.setLiftState(LiftContext.STOPPING_STATE);
        context.getLiftState().stop();
    }
}

class StoppingState extends LiftState {

    @Override
    void open() {
        context.setLiftState(LiftContext.OPENING_STATE);
        context.getLiftState().open();
    }

    @Override
    void close() {

    }

    @Override
    void run() {
        context.setLiftState(LiftContext.RUNNING_STATE);
        context.getLiftState().run();
    }

    @Override
    void stop() {
        System.out.println("电梯停止");
    }
}